/**
 * gntxmms - An XMMS2 client based on libgnt.
 *
 * Copyright 2007, Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer 
 *    in this position and unchanged.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <gnt.h>
#include <gntbox.h>
#include <gntentry.h>
#include <gntlabel.h>
#include <gntline.h>
#include <gnttree.h>

#include "gntxmms.h"

static xmmsc_connection_t *connection;

typedef struct
{
	GntWidget *window;
	
	GntWidget *name;      /* The label with the name of the current song playing */
	GntWidget *time;      /* Shows remaining/total time of the current song playing */
	GntWidget *status;    /* Playing, Paused, Cooking etc. */
	
	GntWidget *playlist;

	int lastid;
} GntXmmsPlayer;

static GntXmmsPlayer player;

static void get_media_info(xmmsc_result_t *result, char **title, char **time);
static void update_playtime(xmmsc_result_t *result, void *null);

static void
playlist_activate_cb(GntTree *tree, GntXmmsPlayer *player)
{
	int id = GPOINTER_TO_INT(gnt_tree_get_selection_data(tree));
	g_printerr("Playing %d\n", id);
	xmms2_stop();
	xmms2_jump(id);
	xmms2_play();

#if 0
	{
		char *title;
		xmmsc_result_t *result;

		result = xmmsc_medialib_get_info(connection, id);
		xmmsc_result_wait(result);

		title = get_media_info(result);

		GntWidget *win = gnt_vbox_new(FALSE);
		gnt_box_set_toplevel(GNT_BOX(win), TRUE);
		gnt_box_add_widget(GNT_BOX(win), gnt_label_new(title));
		gnt_widget_show(win);

		g_free(title);
	}
#endif
}

static void
update_status(xmmsc_result_t *result, void *data)
{
	const char *text = NULL;
	unsigned int status;

	xmmsc_result_wait(result);
	xmmsc_result_get_uint(result, &status);

	switch(status)
	{
		case XMMS_PLAYBACK_STATUS_STOP:
			text = "[ Stopped ]";
			gnt_label_set_text(GNT_LABEL(player.time), "--:--");
			break;
		case XMMS_PLAYBACK_STATUS_PLAY:
			text = "[ Playing ]";
			break;
		case XMMS_PLAYBACK_STATUS_PAUSE:
			text = "[ Paused  ]";
			break;
		default:
			text = "ERROR!!";
			break;
	}

	gnt_label_set_text(GNT_LABEL(player.status), text);
}

static gboolean
playlist_key_pressed_cb(GntTree *tree, const char *key, GntXmmsPlayer *player)
{
#define	X(x, func)	(strcmp(key, x) == 0) func();

	if X("x", xmms2_play)
	else if X("c", xmms2_pause)
	else if X("v", xmms2_stop)
	else if X("b", xmms2_next)
	else if X("z", xmms2_prev)
	else if (key[0] == 27)
	{
		if (strcmp(key+1, GNT_KEY_DEL) == 0)
		{
			gpointer id = gnt_tree_get_selection_data(GNT_TREE(player->playlist));
			gnt_tree_remove(GNT_TREE(player->playlist), id);
		}
	}
	return FALSE;
}

static void
get_media_info(xmmsc_result_t *result, char **title, char **time)
{
	char *text = NULL;
	GString *string = NULL;

	xmmsc_result_wait(result);

	if (time)
	{
		char duration[32] = "??:??";
		if (xmmsc_result_get_dict_entry_type(result, "duration") != XMMSC_RESULT_VALUE_TYPE_NONE)
			xmmsc_entry_format(duration, sizeof(duration) - 1, "${minutes}:${seconds}", result);
		*time = g_strdup(duration);
	}

	if (title)
	{
		string = g_string_new(NULL);
		if (!xmmsc_result_get_dict_entry_str(result, "artist", &text)) {
			/*text = "[Unknown Artist]";*/
			xmmsc_result_get_dict_entry_str(result, "url", &text);
			text = g_path_get_basename(text);
			g_string_append_printf(string, "%s - ", text);
			g_free(text);
		} else
			g_string_append_printf(string, "%s - ", text);

		if (!xmmsc_result_get_dict_entry_str(result, "title", &text))
			text = "[Unknown Title]";
		string = g_string_append(string, text);
		*title = g_string_free(string, FALSE);
	}
}

static void
update_name_cb(xmmsc_result_t *result, void *null)
{
	char *title, *time;
	char *text;
	
	get_media_info(result, &title, &time);

	text = g_strdup_printf("/%s] %s", time, title);
	
	if (text)
		gnt_label_set_text(GNT_LABEL(player.name), text);
	g_free(text);
	g_free(title);
	g_free(time);
}

static void
update_name(xmmsc_result_t *result, void *null)
{
	unsigned int id;

	xmmsc_result_wait(result);
	xmmsc_result_get_uint(result, &id);

	result = xmmsc_medialib_get_info(connection, id);
	xmmsc_result_notifier_set(result, update_name_cb, NULL);
	xmmsc_result_unref(result);

	gnt_tree_set_selected(GNT_TREE(player.playlist), GINT_TO_POINTER(id));

	gnt_tree_set_row_flags(GNT_TREE(player.playlist), GINT_TO_POINTER(player.lastid),
			GNT_TEXT_FLAG_NORMAL);
	gnt_tree_set_row_flags(GNT_TREE(player.playlist), GINT_TO_POINTER(id),
			GNT_TEXT_FLAG_BOLD);
	player.lastid = id;
}

static void
update_position(xmmsc_result_t *result, void *null)
{
	char *text;
	guint32 current;

	result = xmmsc_playlist_current_pos(connection);
	xmmsc_result_wait(result);
	xmmsc_result_get_uint(result, &current);

	result = xmmsc_medialib_get_info(connection, current);
	xmmsc_result_get_dict_entry_str(result, "url", &text);

	if (text)
		gnt_label_set_text(GNT_LABEL(player.name), text);
}

static void
playlist_add_id(unsigned int id)
{
	char *title, *time;
	xmmsc_result_t *result;

	result = xmmsc_medialib_get_info(connection, id);
	xmmsc_result_wait(result);

	get_media_info(result, &title, &time);

	g_printerr("Adding: %d ==> %s\n", id, title);

	gnt_tree_remove(GNT_TREE(player.playlist), GINT_TO_POINTER(id)); /* XXX: something better please */
	gnt_tree_add_row_last(GNT_TREE(player.playlist), GINT_TO_POINTER(id),
			gnt_tree_create_row(GNT_TREE(player.playlist), time, title), NULL);
	g_free(title);
	g_free(time);
}

static void
playlist_refresh(xmmsc_result_t *result)
{
	unsigned int id;

	result = xmmsc_playlist_list(connection);
	xmmsc_result_wait(result);
	for (; xmmsc_result_list_valid(result); xmmsc_result_list_next(result))
	{
		xmmsc_result_get_uint(result, &id);

		playlist_add_id(id);
	}
	xmmsc_result_unref(result);
}

static void
update_playlist(xmmsc_result_t *result, gpointer null)
{
	int type;
	if (!xmmsc_result_get_dict_entry_int32(result, "type", &type))
		return;

	/* XXX: Fix this bad boy */
	playlist_refresh(result);
#if 0
	switch (type)
	{
		case XMMS_PLAYLIST_CHANGED_ADD:
			break;
		case XMMS_PLAYLIST_CHANGED_SHUFFLE:
			break;
		case XMMS_PLAYLIST_CHANGED_REMOVE:
			break;
		case XMMS_PLAYLIST_CHANGED_CLEAR:
			break;
		case XMMS_PLAYLIST_CHANGED_MOVE:
			break;
		case XMMS_PLAYLIST_CHANGED_SORT:
			break;
	}
#endif
}

static void
update_playtime(xmmsc_result_t *result, void *null)
{
	xmmsc_result_t *newr;
	unsigned int time;
	char text[32];

	xmmsc_result_get_uint(result, &time);
	snprintf(text, sizeof(text) - 1, "[%02d:%02d", time / 60000, (time / 1000) % 60);
	gnt_label_set_text(GNT_LABEL(player.time), text);

	/* This is necessary to keep the 'timer' going */
    newr = xmmsc_result_restart(result);
    xmmsc_result_unref(result);
    xmmsc_result_unref(newr);
}

static gboolean
entry_key_pressed_cb(GntEntry *entry, const char *key, GntXmmsPlayer *player)
{
	if (*key == '\r')
	{
		const char *name = gnt_entry_get_text(entry);
		if (g_file_test(name, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
			xmmsc_playlist_add(connection, name);
			gnt_entry_clear(entry);
		}
		return TRUE;
	}
	return FALSE;
}

int main()
{
	GntWidget *window, *tree, *label, *box, *entry;
	xmmsc_result_t *result;

	/* Connect the xmms2d */
	connection = xmmsc_init("gntxmms");
	if (!xmmsc_connect(connection, (char*)getenv("XMMS_PATH")))
	{
		fprintf(stderr, "couldn't connect to xmms2d: %s\n",
				xmmsc_get_last_error(connection));
		return 1;
	}

	xmmsc_mainloop_gmain_init(connection);

	freopen(".error", "w", stderr);
	gnt_init(NULL);

	/* Setup the main window */
	player.window = window = gnt_vbox_new(FALSE);
	gnt_box_set_toplevel(GNT_BOX(window), TRUE);
	gnt_box_set_title(GNT_BOX(window), "GntXmms");
	gnt_box_set_pad(GNT_BOX(window), 0);
	gnt_box_set_fill(GNT_BOX(window), TRUE);

	box = gnt_hbox_new(FALSE);
	gnt_box_set_pad(GNT_BOX(box), 0);
	gnt_box_set_fill(GNT_BOX(box), TRUE);
	player.status = label = gnt_label_new("[ Stopped ]");
	gnt_box_add_widget(GNT_BOX(box), label);

	player.time = label = gnt_label_new("[--:--");
	gnt_box_add_widget(GNT_BOX(box), label);

	player.name = label = gnt_label_new("                       "); /* XXX: This should not be necessary */
	gnt_box_add_widget(GNT_BOX(box), label);

	gnt_box_add_widget(GNT_BOX(window), box);
	gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());
	
	player.playlist = tree = gnt_tree_new_with_columns(2);
	GNT_WIDGET_SET_FLAGS(tree, GNT_WIDGET_NO_BORDER);
	gnt_box_add_widget(GNT_BOX(window), tree);
	gnt_tree_set_col_width(GNT_TREE(tree), 0, 7);
	gnt_tree_set_col_width(GNT_TREE(tree), 1, getmaxx(stdscr) / 2);

	gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());

	box = gnt_hbox_new(FALSE);
	gnt_box_set_fill(GNT_BOX(box), TRUE);
	gnt_box_add_widget(GNT_BOX(window), box);

	gnt_box_add_widget(GNT_BOX(box), gnt_label_new("Add"));

	entry = gnt_entry_new(NULL);
	gnt_widget_set_size(entry, getmaxx(stdscr) / 2 + 5, 1);  /* This should not be necessary */
	gnt_box_add_widget(GNT_BOX(box), entry);

	g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(playlist_key_pressed_cb), &player);
	g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(playlist_activate_cb), &player);
	g_signal_connect(G_OBJECT(entry), "key_pressed", G_CALLBACK(entry_key_pressed_cb), &player);

	gnt_widget_show(player.window);

	/* Setup the connections */
	XMMS_CALLBACK_SET(connection, xmmsc_signal_playback_playtime, 
			update_playtime, NULL);
	XMMS_CALLBACK_SET(connection, xmmsc_broadcast_playback_current_id, 
			update_name, connection);
	XMMS_CALLBACK_SET(connection, xmmsc_broadcast_playback_status,
			update_status, connection);
	XMMS_CALLBACK_SET(connection, xmmsc_broadcast_playlist_changed, 
			update_playlist, connection);

	playlist_refresh(NULL);
	update_status(result = xmmsc_playback_status(connection), NULL);
	xmmsc_result_unref(result);
	update_name(result = xmmsc_playback_current_id(connection), NULL);
	xmmsc_result_unref(result);

	gnt_main();

	xmmsc_disconnect_callback_set(connection, NULL, NULL);
	xmmsc_unref(connection);

	gnt_quit();

	return 0;
}

xmmsc_connection_t *gnt_xmms_get_connection()
{
	return connection;
}

